#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sikle.h"

/* 
 * Get a token from lex, put INTEGER, STRING and WORD into GramelPool, 
 * put STRING data into StringPool, put WORD body into WordPool. 
 */
void translate_integer(SikleState* ss, Lexer* lex, int in_word_decl)
{
  GInteger integer;
  GramelPool* gp = NULL;

  integer.type = GT_INTEGER;
  integer.value = tok_integer(lex);

  gp = in_word_decl ? ss->word_pool : ss->gramel_pool;

  GramelPool_put(gp, GRAMEL(&integer));
}

void translate_string(SikleState* ss, Lexer* lex, int in_word_decl)
{
  GString string;
  NString ns;
  GramelPool* gp = NULL;
  
  string.type = GT_STRING;

  ns = tok_string(lex);
  string.sps = SPString_new(ss->string_pool, ns.data, ns.size);
  NString_delete(ns);

  gp = in_word_decl ? ss->word_pool : ss->gramel_pool;

  GramelPool_put(gp, GRAMEL(&string));
}

void translate_word_call(SikleState* ss, Lexer* lex, int in_word_decl)
{
  NString name = tok_string(lex);
  Word* word;
  GramelPool* gp = NULL;

  gp = in_word_decl ? ss->word_pool : ss->gramel_pool;

  word = Dictionary_get_word(ss->dictionary, name);

  if(word == NULL) {
    error_word_not_defined(&lex->token);
  }
  /* normal word */
  else if(word->type == WT_NORMAL){
    GWord gword;
    
    gword.type = GT_WORD;
    gword.entry = word->u.entry;

    GramelPool_put(gp, GRAMEL(&gword));
  }
  /* builtin word */
  else if(word->type == WT_BUILTIN) {
    GBuiltinWord gword;

    gword.type = GT_BUILTIN_WORD;
    gword.name = SPString_new(ss->string_pool, name.data, name.size);

    GramelPool_put(gp, GRAMEL(&gword));
  }
  NString_delete(name);
}

void translate_word_decl(SikleState* ss, Lexer* lex);
void translate_anonymous_word_decl(SikleState* ss, Lexer* lex, int in_word_decl);

void translate(SikleState* ss, Lexer* lex, TOK end_tok, int in_word_decl)
{
  GEnd end;
  GramelPool* gp = NULL;

  gp = in_word_decl ? ss->word_pool : ss->gramel_pool;

  next_token(lex);

  while(tok_type(lex) != end_tok) {
    switch(tok_type(lex)) {
    case TOK_INTEGER: 
      translate_integer(ss, lex, in_word_decl);
      break;
    case TOK_STRING:
      translate_string(ss, lex, in_word_decl);
      break;
    case TOK_COLON:
      if(in_word_decl) {
	log_msg(LOG_ERROR, "word decl in word decl.", &lex->token);
      }
      translate_word_decl(ss, lex);
      break;
    case TOK_LBRACKET:
      translate_anonymous_word_decl(ss, lex, in_word_decl);
      break;
    case TOK_WORD:
      translate_word_call(ss, lex, in_word_decl);
      break;
    default:
      log_msg(LOG_ERROR, "translate wrong type token.", &lex->token);
    }
    next_token(lex);
  }

  end.type = GT_END;
  GramelPool_put(gp, GRAMEL(&end));
}

void translate_anonymous_word_decl(SikleState* ss, Lexer* lex, int in_word_decl)
{
  GWord word;
  GramelPool* gp = NULL;
  
  word.type = GT_ANONYMOUS_WORD;
  word.entry = ss->word_pool->pc;

  translate(ss, lex, TOK_RBRACKET, TRUE);

  gp = in_word_decl ? ss->word_pool : ss->gramel_pool;

  GramelPool_put(gp, GRAMEL(&word));
}

void translate_word_decl(SikleState* ss, Lexer* lex)
{
  Token tok;
  Word word;
  
  next_token(lex);
  tok = lex->token;
  word.type = WT_NORMAL;
  word.name = tok.v.string;
  word.u.entry = ss->word_pool->pc;
  
  translate(ss, lex, TOK_COLON, TRUE);

  Dictionary_put_word(ss->dictionary, word);
}

void translate_main(SikleState* ss, Lexer* lex)
{
  translate(ss, lex, TOK_EOS, FALSE);
}
